package com.modular.security;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.RegisteredPayload;
import com.modular.common.UserGrantedAuthority;
import com.modular.constant.BaseCodeDesc;
import com.modular.constant.NumberConstant;
import com.modular.exception.ModularException;
import com.modular.json.JackJsonUtil;
import com.modular.utils.SecurityUtil;
import com.modular.vo.security.BaseLogin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class JwtTokenService {
    @Autowired
    private  RedisTemplate<String, Object> redisTemplate;

    private static final String TOKEN_REDIS_KEY = "user_service:token:{}";

    public void createToken(BaseLogin principal) {
        String account = principal.getUserId();
        String format = "{}::{}";
        String subject = StrUtil.format(format,principal.getTokenType(),account);
        Map<String, Object> claims = new HashMap<>();
        claims.put(RegisteredPayload.SUBJECT, subject);
        String token =  JWTUtil.createToken(claims,"11111111111".getBytes());
        principal.setToken(token);
        saveTokenPrincipalToCache(token,principal);
        setSecurityContextAuthentication(principal);
    }

    /**
     * 保存token到redis中
     * @param token
     * @param login
     */
    private void saveTokenPrincipalToCache(String token ,BaseLogin login){
        String reidsKey = StrUtil.format(TOKEN_REDIS_KEY,token);
        redisTemplate.opsForValue().set(reidsKey,login, NumberConstant.ONE, TimeUnit.DAYS);
    }

    /**
     * 保存token到redis中
     * @param token
     */
    public BaseLogin getTokenPrincipalToCache(String token){
        try {
            String reidsKey = StrUtil.format(TOKEN_REDIS_KEY, token);
            Object userVo = redisTemplate.opsForValue().get(reidsKey);
            if (ObjectUtil.isNull(userVo)) {
                throw new ModularException(BaseCodeDesc.TOKEN_UNDEFIND);
            }
            return (BaseLogin) userVo;
        }catch (Exception e){
            return null;
        }

    }

    public  boolean logout(String token) {
        String reidsKey = StrUtil.format(TOKEN_REDIS_KEY,token);
        redisTemplate.delete(reidsKey);
        return true;

    }

    /**
     * 将数据保存在
     * @param principal
     */
    public void setSecurityContextAuthentication(BaseLogin principal) {
        if (principal != null) {
            List<String> authorities = principal.getAuthorities();
            Set<? extends GrantedAuthority> authorityList = createAuthorityList(authorities);
            Authentication authentication = new UsernamePasswordAuthenticationToken(principal, (Object)null, authorityList);
            SecurityContext securityContext = SecurityContextHolder.getContext();
            securityContext.setAuthentication(authentication);
        }
    }

    private Set<? extends GrantedAuthority> createAuthorityList(List<String> authorities) {
        return !CollUtil.isEmpty(authorities) ? authorities.stream().filter(StrUtil::isNotBlank).map(UserGrantedAuthority::getInstance).collect(Collectors.toSet()) : Collections.emptySet();
    }


}
